/**
 * Javada - Copyright 2009  Rapita Systems Ltd.
 * http://www.rapitasystems.com  javada@rapitasystems.com
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.rapitasystems.javada;

import java.io.File;
import java.io.FileReader;
import java.io.PushbackReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import net.sf.eclipsecorba.idl.ModelBuilder;
import net.sf.eclipsecorba.idl.PreprocessingLexer;
import net.sf.eclipsecorba.idl.Specification;
import net.sf.eclipsecorba.idl.node.ASpecification;
import net.sf.eclipsecorba.idl.node.Start;
import net.sf.eclipsecorba.idl.parser.Parser;
import net.sf.eclipsecorba.idl.parser.ParserException;

public class IdlParser {

	private HashMap<File, Specification> parsedSpecs = new HashMap<File, Specification>();
	private LinkedList<File> parseQueue = new LinkedList<File>();
	
	/**
	 * Parses an IDL file and returns the corresponding model
	 * @param file the file to parse
	 * @param includeDirs directories to search for included idl files
	 * @return Specification object containing the parsed IDL model
	 */
	public Specification parseIDLFile(File file, List<File> includeDirs) {
		// Check if spec has already been parsed
		Specification spec = parsedSpecs.get(file);
		if (spec != null)
			return spec;
		
		// Parse spec
		System.out.println("Parsing " + file.toString());
		try {
			PreprocessingLexer lexer = new PreprocessingLexer(new PushbackReader(new FileReader(file), 255));
			
			// Now parse file
			Preprocessor preprocessor = new Preprocessor(includeDirs, this, file);
			lexer.setPreprocessor(preprocessor);
			Parser parser = new Parser(lexer);
			Start start = parser.parse();
			ModelBuilder builder = new ModelBuilder(
					file.getName(), 
					preprocessor.getIncludes(), 
					preprocessor.getDefinitions(), 
					lexer.getComments(),
					new HashMap<String, String>());
			spec = builder.buildModel((ASpecification) start.getPSpecification());
			
			// Add to map and return
			parsedSpecs.put(file, spec);
			return spec;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		} 
	}
	
	public Specification parse(File parent, String filename, List<File> includeDirs) throws ParserException {
		// Find in include directories
		for (File dir : includeDirs) {
			File f = new File(dir.getAbsoluteFile() + "/" + filename);
			if (f.exists()) {
				if (parseQueue.contains(f))
					throw new ParserException(null, "Circular dependency for " + filename + " in " + parent.getName());
				parseQueue.addLast(f);
				Specification spec = parseIDLFile(f, includeDirs);
				parseQueue.removeLast();
				return spec;
			}
		}
		return null;
	}
}
